<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.3.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chuangges.gitee.io","root":"/","scheme":"Pisces","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="基础介绍、模块机制、应用场景、性能优化">
<meta property="og:type" content="article">
<meta property="og:title" content="Node.js 主要内容">
<meta property="og:url" content="https://chuangges.gitee.io/2019/06/16/7-1-Node%E5%9F%BA%E7%A1%80/index.html">
<meta property="og:site_name" content="闯哥要去流浪了">
<meta property="og:description" content="基础介绍、模块机制、应用场景、性能优化">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://chuangges.gitee.io/images/js/node-framework.png">
<meta property="article:published_time" content="2019-06-15T16:49:49.000Z">
<meta property="article:modified_time" content="2023-11-06T06:13:21.399Z">
<meta property="article:author" content="chuangges">
<meta property="article:tag" content="JS 扩展">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://chuangges.gitee.io/images/js/node-framework.png">

<link rel="canonical" href="https://chuangges.gitee.io/2019/06/16/7-1-Node%E5%9F%BA%E7%A1%80/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Node.js 主要内容 | 闯哥要去流浪了</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="闯哥要去流浪了" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">闯哥要去流浪了</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">愿你岁月可回首，且以深情共白头</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chuangges.gitee.io/2019/06/16/7-1-Node%E5%9F%BA%E7%A1%80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/chuang.png">
      <meta itemprop="name" content="chuangges">
      <meta itemprop="description" content="chuangge's blog.">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="闯哥要去流浪了">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Node.js 主要内容
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-06-16 00:49:49" itemprop="dateCreated datePublished" datetime="2019-06-16T00:49:49+08:00">2019-06-16</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2023-11-06 14:13:21" itemprop="dateModified" datetime="2023-11-06T14:13:21+08:00">2023-11-06</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JS-%E6%89%A9%E5%B1%95/" itemprop="url" rel="index"><span itemprop="name">JS 扩展</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>42k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>39 分钟</span>
            </span>
            <div class="post-description">基础介绍、模块机制、应用场景、性能优化</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、基础介绍"><a href="#一、基础介绍" class="headerlink" title="一、基础介绍"></a>一、基础介绍</h1><blockquote>
<p>运行在服务端的 JS 环境，是基于 Chrome JavaScript V8 引擎建立的平台，用于开发和运行视频流网站、单页应用或在线聊天应用等<code>io密集型网络应用</code>。它封装了 V8 引擎并引入 CommonJS 规范而解决了 JS 比较慢和乱的问题，通过单线程和异步事件驱动机制实现了较强的并发处理能力，适用于<code>高并发、I/O 密集、少量业务逻辑</code>的场景。但是不适合处理<code>密集计算和复杂逻辑</code>，因为那可能会阻塞应用中运行的单线程。</p>
</blockquote>
<ul>
<li><strong>优点</strong>：轻量高效、事件驱动模型、异步非阻塞 I&#x2F;O 模型、单进程单线程应用程序。</li>
<li><strong>不足</strong>：不适合处理复杂逻辑、不适合计算密集型应用、不适合单用户多任务的程序、代码某个环节报错则整个系统崩溃、只支持单核 CPU 而不能充分利用多核 CPU 服务器。</li>
<li><strong>前端应用</strong>：<code>模块捆绑器</code>(类似 Webpack&#x2F;Vite 将代码片段捆绑为一个文件而方便运行)、<code>代码润色器</code>(类似 ESLint 检测和修改代码)、<code>npm 包</code>(帮助编程)、<code>样式设计</code>(编写组件库)。</li>
<li><strong>后端应用</strong>：<code>数据库集成</code>(支持 JS 进行数据库操作)、<code>实时应用</code>(事件驱动机制和非阻塞I&#x2F;O模型实现密集通信)、<code>网络和API调用</code>(在线论坛等支持处理请求的同时继续其它工作)。</li>
<li><strong>应用案例</strong>：<code>Uber</code>(快速处理大量数据和修正故障)、<code>Netflix</code>(视频流媒体服务)、<code>LinkedIn</code>(提升性能和资源利用率)、<code>贝宝</code>(允许通过 JS 开发浏览器和服务器应用程序)。</li>
</ul>
<h2 id="运行机制"><a href="#运行机制" class="headerlink" title="运行机制"></a>运行机制</h2><blockquote>
<p>同步异步指操作任务是否按顺序执行，阻塞非阻塞指 IO 操作是否影响主线程执行其它代码。</p>
</blockquote>
<ul>
<li><strong>单线程</strong>：通过一个主线程处理所有的请求，注意异步操作是通过线程池来完成的。</li>
<li><strong>异步非阻塞</strong>：主线程接收到操作请求后就作为一个事件放入任务队列，然后继续接收其他请求，如果有耗时操作则交给不同的工作线程去执行，所以主线程速度快而且不会阻塞。</li>
<li><strong>事件驱动</strong>：主线程按顺序将所有操作都注册为一个事件并等待触发的方式。主线程首先执行完同步操作，然后通过事件循环机制查看任务队列中的事件并将异步事件交给工作线程。</li>
</ul>
<h2 id="功能架构"><a href="#功能架构" class="headerlink" title="功能架构"></a>功能架构</h2>  <div align="center">
      <img src="" data-original="/images/js/node-framework.png" alt="Node Framework" width="100%">
  </div>


<h2 id="安装配置"><a href="#安装配置" class="headerlink" title="安装配置"></a>安装配置</h2><blockquote>
<p>本质是把 NodeJS 执行程序复制到一个目录 (建议不要安装在 C 盘而修改默认地址为 “D:\nodejs&quot;)，然后配置安装管理和环境变量以实现统一管理安装包和全局使用 node 命令。</p>
</blockquote>
  <figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">====================== Window 安装 ========================</span><br><span class="line"><span class="number">1</span>、官网下载 Windows Installer.msi <span class="number">64</span>位安装包 (<span class="built_in">zip</span>压缩包解压即可)。</span><br><span class="line"></span><br><span class="line"><span class="number">2</span>、常用命令：查看版本 node -v 交互模式 node、执行文件 node home.js。</span><br><span class="line"></span><br><span class="line"><span class="number">3</span>、配置包文件管理：统一管理通过 npm 全局安装的第三方包及其缓存。</span><br><span class="line">  <span class="comment"># 新建文件夹并执行命令：node_global、node_cache</span></span><br><span class="line">  npm config <span class="built_in">set</span> cache <span class="string">&quot;D:\nodejs\node_cache&quot;</span></span><br><span class="line">  npm config <span class="built_in">set</span> prefix <span class="string">&quot;D:\nodejs\node_global&quot;</span></span><br><span class="line">  <span class="comment"># 修改文件：node_modules\npm\npmrc</span></span><br><span class="line">  prefix = <span class="string">&quot;D:\nodejs\node_global&quot;</span></span><br><span class="line">  cache = <span class="string">&quot;D:\nodejs\node_global&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="number">4</span>、环境配置：全局使用命令。path 默认路径、NODE_PATH 额外的模块搜索路径。</span><br><span class="line">  用户变量 PATH 末尾添加 <span class="string">&quot;;D:\nodejs\node_global&quot;</span></span><br><span class="line">  系统变量新增 NODE_PATH: <span class="string">&quot;D:\nodejs\node_global\node_modules&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">===================== Mac Homebrew 安装 =====================</span><br><span class="line">brew install nodejs</span><br><span class="line">brew install homebrew/versions/node</span><br><span class="line">brew install homebrew/versions/node5</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">===================== Mac nvm 安装多版本 =====================</span><br><span class="line"><span class="number">1</span>、安装 nvm：当前用户目录下安装，不成功时可以执行几次</span><br><span class="line">  cd ~/、git clone https://github.com/nvm-sh/nvm.git</span><br><span class="line">  cd nvm &amp;&amp; ./install.sh</span><br><span class="line"></span><br><span class="line"><span class="number">2</span>、环境配置：直接进入某目录 Finder、command + shift + G</span><br><span class="line">  vim ~/.bash_profile    // i 编辑、esc 退出、:wq 保存</span><br><span class="line">  <span class="comment"># nvm</span></span><br><span class="line">  export NVM_DIR=<span class="string">&quot;$HOME/.nvm&quot;</span></span><br><span class="line">  [ -s <span class="string">&quot;$NVM_DIR/nvm.sh&quot;</span> ] &amp;&amp; \. <span class="string">&quot;$NVM_DIR/nvm.sh&quot;</span></span><br><span class="line">  [ -s <span class="string">&quot;$NVM_DIR/bash_completion&quot;</span> ] &amp;&amp; \. <span class="string">&quot;$NVM_DIR/bash_completion&quot;</span></span><br><span class="line">  <span class="comment"># node</span></span><br><span class="line">  export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node/</span><br><span class="line">  export NVM_IOJS_ORG_MIRROR=https://npmmirror.com/mirrors/iojs/</span><br><span class="line"></span><br><span class="line">  source ~/.bash_profile    // 当前窗口生效</span><br><span class="line"></span><br><span class="line">  vim ~/.zshrc</span><br><span class="line">  source ~/.bash_profile  </span><br><span class="line">  source ~/.zshrc           // 永久生效</span><br><span class="line"></span><br><span class="line"><span class="number">3</span>、nvm 常用命令</span><br><span class="line">nvm ls-remote               // 查看 node 可用版本  </span><br><span class="line">nvm install <span class="number">14.19</span><span class="number">.3</span>         // 安装 node 指定版本</span><br><span class="line">nvm install --lts           // 安装 node 最新稳定版本</span><br><span class="line">nvm uninstall <span class="number">11.15</span><span class="number">.0</span>       // 卸载 node 指定版本</span><br><span class="line">nvm alias default <span class="number">11.15</span><span class="number">.0</span>   // 设置 node 默认版本</span><br><span class="line">nvm use <span class="number">11.15</span><span class="number">.0</span>             // 使用 node 指定版本</span><br><span class="line">nvm <span class="built_in">list</span>                    // 查看 node 已安装版本</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">===================== Node 安装 cnpm =====================</span><br><span class="line">npm install cnpm@<span class="number">7.1</span><span class="number">.0</span> -g --registry=https://registry.npm.taobao.org</span><br><span class="line">npm i cnpm -g --registry=https://registry.npmmirror.com/</span><br><span class="line"></span><br><span class="line">npm config <span class="built_in">set</span> registry https://registry.npm.taobao.org // 失败时的方案</span><br><span class="line">http://registry.npm.taobao.org      老版本镜像</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">===================== 调试工具 nodemon ===================</span><br><span class="line"><span class="comment"># 安装、启动、app.js：监听代码更新并重启服务</span></span><br><span class="line">cnpm install -g nodemon、nodemon app  </span><br><span class="line"></span><br><span class="line">var http = require(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line">http.createServer((req, res) =&gt; &#123;</span><br><span class="line">    res.end(<span class="string">&#x27;hello node&#x27;</span>);</span><br><span class="line">&#125;).listen(<span class="number">3000</span>)</span><br></pre></td></tr></table></figure>


<h1 id="二、模块机制"><a href="#二、模块机制" class="headerlink" title="二、模块机制"></a>二、模块机制</h1><h2 id="模块规范"><a href="#模块规范" class="headerlink" title="模块规范"></a>模块规范</h2><ul>
<li><strong>模块加载</strong>：CommonJS 规范的 require 加载、module.exports 导出。<ul>
<li><code>核心模块</code>：本身已被编译好并存储在内存，只传入模块名称即可。</li>
<li><code>第三方模块</code>：存储于 node_modules，加载时从当前目录到根目录 node_modules 依次查找，和核心模块一样只需要传入模块名称而不要添加后缀和路径等。</li>
<li><code>自定义模块</code>：必须使用相对路径，引入文件夹则默认加载其 index.js。</li>
</ul>
</li>
<li><strong>模块缓存</strong><ul>
<li>模块会在第一次 require 时缓存，多次 require 不会导致模块代码被执行多次。</li>
<li>浏览器 JS 只缓存文件，Node 模块缓存的是编译和执行之后的对象。</li>
<li>require.cache 对象代表 Node 模块缓存区，缓存模块以属性方式加入该对象，可以通过 <code>require.cache[模块标识符]</code> 访问具体的缓存模块，可以 delete 该缓存。</li>
</ul>
</li>
<li><strong>模块变量</strong><ul>
<li>全局对象：<code>global</code> (类似浏览器 window)、<code>process</code> (指向内置模块 process 允许开发者与当前进程互动)、<code>console</code> (指向内置模块 console 支持命令行环境的输入输出)。</li>
<li>全局函数：require、setTimeout、setInterval、clearTimeout、clearInterval。</li>
<li>全局变量：<code>_filename、_dirname</code> (指向当前运行脚本的文件名、所在目录)。</li>
<li>模块变量：<code>module</code> (当前模块对象)、<code>module.exports</code>**：(模块的导出对象)、<code>module.filename</code> (模块解析后的文件名)、<code>exports</code> (指向 module.exports 的变量)。</li>
</ul>
</li>
<li><strong>模块包规范</strong><ul>
<li>NodeJS 通过包括一个目录及其文件的包来统一管理一组具有相互依赖关系的模块。</li>
<li>目录文件：<code>package.json</code> (描述文件)、<code>bin</code> (可执行的二进制文件)、<code>lib</code> (待加载的 js 文件)、<code>doc</code> (说明文档)、<code>test</code> (单元测试用例)、<code>node_modules</code> (本地依赖包)。</li>
</ul>
</li>
</ul>
<h2 id="核心模块"><a href="#核心模块" class="headerlink" title="核心模块"></a>核心模块</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line">=========================== <span class="variable constant_">HTTP</span> ============================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 客户端请求</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 1、创建服务器：http.get / request(opts, fn)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 2、监听请求：req.on(&quot;response / error&quot;, fn)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 3、监听响应信息：res.on(&quot;data / end / close&quot;, fn)</span></span><br><span class="line"><span class="comment">* <span class="doctag">@param</span> 4、处理响应信息：res.setEncoding/pause/resume/statusCode</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">http.<span class="title function_">get</span>(&#123;</span><br><span class="line">    <span class="attr">host</span>: <span class="string">&#x27;localhost&#x27;</span>,</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/user?name=tom&amp;age=22&#x27;</span>,</span><br><span class="line">    <span class="attr">port</span>: <span class="number">3000</span></span><br><span class="line">&#125;,  <span class="keyword">function</span>(<span class="params">res</span>)&#123;</span><br><span class="line">    res.<span class="title function_">setEncoding</span>(<span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line">    res.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>,<span class="keyword">function</span>(<span class="params">data</span>)&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;返回数据：&#x27;</span>+ data)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 服务端响应</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 1、创建服务器：http.createServer(fn)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 2、监听请求：server.on(&quot;request / close&quot;, fn)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 3、获取请求数据：server.on(&quot;data / end / close&quot;, fn)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 4、处理响应信息：setHeader、writeHead、write、end</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">let</span> server = http.<span class="title function_">createServer</span>();</span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;服务器启动成功：http://localhost:3000/&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> method = req.<span class="property">method</span>.<span class="title function_">toLowerCase</span>();</span><br><span class="line">    <span class="keyword">let</span> &#123;query, pathname&#125; = <span class="built_in">require</span>(<span class="string">&#x27;url&#x27;</span>).<span class="title function_">parse</span>(req.<span class="property">url</span>, <span class="literal">true</span>);</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;</span><br><span class="line">        <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/json;charset=utf-8&quot;</span>, <span class="comment">// 乱码</span></span><br><span class="line">        <span class="string">&quot;access-control-allow-origin&quot;</span>: <span class="string">&quot;*&quot;</span>  <span class="comment">// cors 头允许跨域</span></span><br><span class="line">    &#125;)</span><br><span class="line">    res.<span class="title function_">write</span>(<span class="string">`请求接口：<span class="subst">$&#123;pathname&#125;</span>`</span>)</span><br><span class="line">    <span class="keyword">switch</span> (pathname) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;/&#x27;</span>:</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;/index&#x27;</span>:</span><br><span class="line">            res.<span class="title function_">end</span>(<span class="string">&#x27;index.html&#x27;</span>)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;/user&#x27;</span>:</span><br><span class="line">            res.<span class="title function_">end</span>(<span class="string">`<span class="subst">$&#123;query.name&#125;</span>年龄为<span class="subst">$&#123;query.age&#125;</span>`</span>)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">            res.<span class="title function_">end</span>(<span class="string">&#x27;404 Error&#x27;</span>)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> body = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    req.<span class="title function_">setEncoding</span>(<span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">    req.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="keyword">function</span> (<span class="params">chunk</span>) &#123;</span><br><span class="line">        body += chunk</span><br><span class="line">    &#125;);</span><br><span class="line">    req.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> data = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(body);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (er) &#123;</span><br><span class="line">            res.<span class="property">statusCode</span> = <span class="number">400</span>;</span><br><span class="line">            <span class="keyword">return</span> res.<span class="title function_">end</span>(<span class="string">&#x27;error: &#x27;</span> + er.<span class="property">message</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        res.<span class="title function_">write</span>(<span class="keyword">typeof</span> data);</span><br><span class="line">        res.<span class="title function_">end</span>();</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">8080</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">========================== <span class="variable constant_">URL</span> ===============================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 处理客户端请求的 URL。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> parse：字符串地址转对象。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> format：对象转为字符串。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> resolve：对传入参数通过 / 拼接。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> url = <span class="built_in">require</span>(<span class="string">&quot;url&quot;</span>)</span><br><span class="line">url.<span class="title function_">parse</span>(<span class="string">&quot;http://user@host.com:8080/p?query=a#hash&quot;</span>, <span class="literal">true</span>)</span><br><span class="line">url.<span class="title function_">format</span>(&#123; <span class="attr">protocol</span>: <span class="string">&quot;http:&quot;</span>, <span class="attr">host</span>: <span class="string">&quot;182:60&quot;</span>, <span class="attr">port</span>: <span class="string">&quot;60&quot;</span> &#125;)</span><br><span class="line">url.<span class="title function_">resolve</span>(<span class="string">&quot;http://whitemu.com&quot;</span>, <span class="string">&quot;gulu&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">========================== <span class="title class_">Querystring</span> =======================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 处理客户端请求传递的参数。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> parse、stringify：字符串和对象的转换。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> escape、unescape：使传入的字符串的编码和解码。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> querystring = <span class="built_in">require</span>(<span class="string">&#x27;querystring&#x27;</span>)</span><br><span class="line">querystring.<span class="title function_">parse</span>(<span class="string">&quot;name=tom&amp;sex=man&amp;sex=women&quot;</span>)</span><br><span class="line">querystring.<span class="title function_">stringify</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;tom&#x27;</span>, <span class="attr">sex</span>: [<span class="string">&#x27;man&#x27;</span>, <span class="string">&#x27;women&#x27;</span>]&#125;)</span><br><span class="line">querystring.<span class="built_in">escape</span>(<span class="string">&quot;name=慕白&quot;</span>)</span><br><span class="line">querystring.<span class="built_in">unescape</span>(<span class="string">&#x27;name%3D%E6%85%95%E7%99%BD&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">=========================== <span class="title class_">Path</span> ==============================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 操作文件路径。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 获取路径信息：dirname 路径、extname 扩展名、basename 文件名。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 路径拼接：join 拼接、resolve 绝对路径、relative 解析相对路径。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 路径处理：parse 对象、format 字符、normalize 标准、isAbsolute。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line">path.<span class="title function_">dirname</span>(<span class="string">&#x27;/foo/bar/baz/asdf/a.txt&#x27;</span>)</span><br><span class="line"></span><br><span class="line">path.<span class="title function_">join</span>(<span class="string">&#x27;/foo&#x27;</span>, <span class="string">&#x27;bar&#x27;</span>, <span class="string">&#x27;baz/asdf&#x27;</span>, <span class="string">&#x27;..&#x27;</span>)</span><br><span class="line">path.<span class="title function_">resolve</span>(<span class="string">&#x27;www&#x27;</span>, <span class="string">&#x27;js/upload&#x27;</span>, <span class="string">&#x27;../mod.js&#x27;</span>)</span><br><span class="line">path.<span class="title function_">relative</span>(<span class="string">&#x27;C:/test/aaa&#x27;</span>, <span class="string">&#x27;C:/bbb&#x27;</span>)</span><br><span class="line"></span><br><span class="line">path.<span class="title function_">parse</span>(<span class="string">&#x27;/home/user/dir/file.txt&#x27;</span>)</span><br><span class="line">path.<span class="title function_">format</span>(&#123; <span class="attr">dir</span>: <span class="string">&#x27;/tmp&#x27;</span>, <span class="attr">name</span>: <span class="string">&#x27;hello&#x27;</span>, <span class="attr">ext</span>: <span class="string">&#x27;.js&#x27;</span> &#125;)</span><br><span class="line">path.<span class="title function_">normalize</span>(<span class="string">&#x27;a/../user/bin&#x27;</span>)</span><br><span class="line">path.<span class="title function_">isAbsolute</span>(<span class="string">&#x27;/foo/bar&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">=========================== <span class="title class_">Events</span> ==============================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 处理多状态的异步操作</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 事件创建：new require(&quot;events&quot;).EventEmitter()</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 事件处理：on/once 监听、emit 触发、removeListener 删除</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> events = <span class="built_in">require</span>(<span class="string">&quot;events&quot;</span>)</span><br><span class="line"><span class="keyword">let</span> emitter = <span class="keyword">new</span> events.<span class="title class_">EventEmitter</span>()</span><br><span class="line">emitter.<span class="title function_">on</span>(<span class="string">&quot;connection&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;linked Success&quot;</span>);</span><br><span class="line">&#125;)</span><br><span class="line">emitter.<span class="title function_">emit</span>(<span class="string">&quot;connection&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">=========================== <span class="title class_">Events</span> ==============================</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 服务端操作文件，同步时在以下异步接口后加 Sync 比如 readFileSync</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 操作文件：readFile、writeFile、appendFile、rename、unlink</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 操作目录：mkdir 创建、readdir、rmdir 删除目录、chmod 修改权限</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> fs = <span class="built_in">require</span>(<span class="string">&quot;fs&quot;</span>);</span><br><span class="line">fs.<span class="title function_">stat</span>(<span class="string">&#x27;input.txt&#x27;</span>, <span class="keyword">function</span> (<span class="params">err, stats</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err) </span><br><span class="line">    stats.<span class="title function_">isFile</span>()        <span class="comment">// 是否为文件</span></span><br><span class="line">    stats.<span class="title function_">isDirectory</span>()   <span class="comment">// 是否为目录</span></span><br><span class="line">&#125;)</span><br><span class="line">fs.<span class="title function_">writeFile</span>(<span class="string">&#x27;input.txt&#x27;</span>, <span class="string">&#x27;写入文件的内容&#x27;</span>,  <span class="keyword">function</span>(<span class="params">err</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err) </span><br><span class="line">    fs.<span class="title function_">readFile</span>(<span class="string">&#x27;input.txt&#x27;</span>, <span class="keyword">function</span> (<span class="params">err, data</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err) </span><br><span class="line">        <span class="keyword">let</span> data_str = data.<span class="title function_">toString</span>()</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="Stream-流"><a href="#Stream-流" class="headerlink" title="Stream 流"></a>Stream 流</h2><blockquote>
<p>一组有序的、有起止点的字节数据传输方式，本质是 <code>buffer</code> 对象的高级封装和 EventEmitter 类的实例，常用于文件上传、视频读取等异步操作。<code>流类型</code>可分为 Readable 可读、Writable 可写、Duplex 可读写、Transform 可转换，<code>流模式</code>则根据创建时传入参数 Object&#x2F;Buffer 确定并且不可修改但是可拼接转换出一个新流，<code>注意</code>：Writable 流中写入 null 表示数据已写入完成而继续写入报错，Readable 流中读取到 null 表示数据已读取完毕。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 创建：createReadStream、createWriteStream</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 事件：open、data、end、error、finish</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 流向：Readable 流 --&gt; Duplex 流 --&gt; Writable 流</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// 文件系统</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> txt = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>).<span class="title function_">join</span>(__dirname, <span class="string">&#x27;./1.txt&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> rStream = fs.<span class="title function_">createReadStream</span>(txt, &#123;</span><br><span class="line">    <span class="attr">flags</span>: <span class="string">&#x27;r&#x27;</span>,	       <span class="comment">// 打开模式：w 写、r 读、a 追加</span></span><br><span class="line">    <span class="attr">mode</span>: <span class="number">0o666</span>,       <span class="comment">// 文件模式：0o222 可写入、0o444 可读取</span></span><br><span class="line">    <span class="attr">encoding</span>: <span class="string">&#x27;utf8&#x27;</span>,  <span class="comment">// 编码格式</span></span><br><span class="line">    <span class="attr">autoClose</span>: <span class="literal">true</span>,   <span class="comment">// 错误或结束时是否自动关闭</span></span><br><span class="line">    <span class="attr">highWaterMark</span>: <span class="number">9</span>,  <span class="comment">// 单位 KB，默认为 16KB</span></span><br><span class="line">    <span class="attr">start</span>: <span class="number">0</span>,          <span class="comment">// 开始读取范围</span></span><br><span class="line">    <span class="attr">end</span>: <span class="number">0</span>             <span class="comment">// 结束读取范围</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 直接使用 stream 模块</span></span><br><span class="line"><span class="keyword">const</span> stream = <span class="built_in">require</span>(<span class="string">&#x27;stream&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> rStream = <span class="keyword">new</span> stream.<span class="title class_">Readable</span>()</span><br><span class="line"><span class="keyword">const</span> wStream = <span class="keyword">new</span> stream.<span class="title class_">Writable</span>()</span><br><span class="line"><span class="keyword">const</span> dStream = <span class="keyword">new</span> stream.<span class="title class_">Duplex</span>()</span><br><span class="line"><span class="keyword">const</span> tStream = <span class="keyword">new</span> stream.<span class="title class_">Transform</span>()</span><br><span class="line"> </span><br><span class="line"></span><br><span class="line"><span class="comment">// Buffer 整体缓冲、Stream 分块缓冲</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./test.file&#x27;</span>, <span class="function">(<span class="params">err, buffer</span>) =&gt;</span> &#123;</span><br><span class="line">    fs.<span class="title function_">writeFile</span>(<span class="string">&#x27;./test.buffer.file&#x27;</span>, buffer, <span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;finish&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line">fs.<span class="title function_">createReadStream</span>(<span class="string">&#x27;./test.file&#x27;</span>)</span><br><span class="line">.<span class="title function_">pipe</span>(fs.<span class="title function_">createWriteStream</span>(<span class="string">&#x27;./test.stream.file&#x27;</span>))</span><br><span class="line">.<span class="title function_">on</span>(<span class="string">&#x27;finish&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;finish&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 读取流</span></span><br><span class="line"><span class="keyword">var</span> data = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="keyword">var</span> readStream = fs.<span class="title function_">createReadStream</span>(<span class="string">&#x27;input.txt&#x27;</span>) </span><br><span class="line">readStream.<span class="title function_">setEncoding</span>(<span class="string">&#x27;UTF8&#x27;</span>)  </span><br><span class="line">readStream.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="keyword">function</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">    data += chunk</span><br><span class="line">&#125;)</span><br><span class="line">readStream.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(data)</span><br><span class="line">&#125;)</span><br><span class="line">readStream.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">stack</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 写入流</span></span><br><span class="line"><span class="keyword">var</span> data = <span class="string">&#x27;要写入的内容&#x27;</span></span><br><span class="line"><span class="keyword">var</span> writeStream = fs.<span class="title function_">createWriteStream</span>(<span class="string">&#x27;output.txt&#x27;</span>)</span><br><span class="line">writeStream.<span class="title function_">write</span>(data, <span class="string">&#x27;UTF8&#x27;</span>)</span><br><span class="line">writeStream.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Buffer</span>(<span class="string">&#x27;写入二进制...\n&#x27;</span>, <span class="string">&#x27;utf-8&#x27;</span>));</span><br><span class="line">writeStream.<span class="title function_">end</span>()      <span class="comment">// 标记文件末尾</span></span><br><span class="line">writeStream.<span class="title function_">on</span>(<span class="string">&#x27;finish&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;写入完成&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">writeStream.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">stack</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 链式流：通过连接输出流到其它流并创建流操作，如下压缩和解压</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&quot;fs&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> zlib = <span class="built_in">require</span>(<span class="string">&#x27;zlib&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> data = <span class="string">&#x27;test dfddgfdgfdgfdgfd jkwu&#x27;</span></span><br><span class="line">fs.<span class="title function_">createReadStream</span>(<span class="string">&#x27;input.txt&#x27;</span>)</span><br><span class="line">    .<span class="title function_">pipe</span>(zlib.<span class="title function_">createGzip</span>())</span><br><span class="line">    .<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, onerror)</span><br><span class="line">    .<span class="title function_">pipe</span>(fs.<span class="title function_">createWriteStream</span>(<span class="string">&#x27;input.txt.gz&#x27;</span>))</span><br><span class="line">fs.<span class="title function_">createReadStream</span>(<span class="string">&#x27;input.txt.gz&#x27;</span>)</span><br><span class="line">    .<span class="title function_">pipe</span>(zlib.<span class="title function_">createGunzip</span>())</span><br><span class="line">    .<span class="title function_">pipe</span>(fs.<span class="title function_">createWriteStream</span>(<span class="string">&#x27;input.txt&#x27;</span>))  </span><br></pre></td></tr></table></figure>


<h1 id="三、进程机制"><a href="#三、进程机制" class="headerlink" title="三、进程机制"></a>三、进程机制</h1><blockquote>
<p>资源分配的最小单位，Node 启动一个服务并运行一个实例就是开一个服务进程。多进程之间的地址空间和数据栈相互独立，只有建立了 IPC 通信才可以数据共享。线程则是 cpu 调度的最小单位，一个进程下的多线程有独立堆栈但没有独立的地址空间。<code>单线程</code>就是一个进程只开一个线程，所以 JS 同步耗时操作过多时会造成阻塞。单线程模型的 <code>NodeJS</code> 基于事件驱动和异步非阻塞模式应用于高并发场景，但异常错误会引起整个应用退出。<code>Nginx</code> 也是采用事件驱动模式避免了多线程的线程创建、上下文切换的开销，用于高性能的服务器而不适合业务。</p>
</blockquote>
<h2 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、linux 命令</span></span><br><span class="line">ps -ef               <span class="comment">// 查看电脑启动的所有进程 </span></span><br><span class="line">ps -ef| grep pid     <span class="comment">// 查看电脑启动的某个进程 </span></span><br><span class="line">lsof -<span class="attr">i</span>:port         <span class="comment">// 查看端口占用的进程信息</span></span><br><span class="line">netstat -anvp tcp    <span class="comment">// 查看 tcp 端口占用情况</span></span><br><span class="line">top -pid pid         <span class="comment">// 查看进程状态</span></span><br><span class="line">pstree -p pid        <span class="comment">// 查看子进程</span></span><br><span class="line">ps -M pid            <span class="comment">// 查看线程</span></span><br><span class="line">kill -<span class="number">9</span> pid          <span class="comment">// 通过 pid 杀死进程</span></span><br><span class="line">pkill command        <span class="comment">// 通过进程名杀死进程</span></span><br><span class="line">e.<span class="property">g</span>. pkill node      <span class="comment">// 杀死所有 node 应用</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、Node 进程</span></span><br><span class="line"><span class="comment">// 杀死进程</span></span><br><span class="line">process.<span class="title function_">exit</span>(code) </span><br><span class="line"><span class="comment">// 启动进程</span></span><br><span class="line">child_process.<span class="title function_">fork</span>();  </span><br><span class="line"><span class="comment">// 重启进程：先 fork 再 exit</span></span><br><span class="line">child_process.<span class="title function_">fork</span>();  </span><br><span class="line">process.<span class="title function_">exit</span>(code)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、Node 服务热重启：一般是滚动发布，即一个个服务轮流进行重启。</span></span><br><span class="line">workder.<span class="title function_">emit</span>(<span class="string">&#x27;disconnect&#x27;</span>)    <span class="comment">// 1、通知主进程不再派发任务</span></span><br><span class="line"><span class="title function_">sleep</span>(<span class="number">10000</span>)</span><br><span class="line">workder.<span class="title function_">kill</span>()    <span class="comment">// 2、等待连接超时时间，避免终止未完成任务</span></span><br><span class="line">cluster.<span class="title function_">fork</span>()    <span class="comment">// 3、关闭并重启服务</span></span><br></pre></td></tr></table></figure>


<h2 id="进程管理"><a href="#进程管理" class="headerlink" title="进程管理"></a>进程管理</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、process 模块：读取或设置进程信息的全局对象</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 进程信息</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> title：进程名称</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> pid： 进程的 id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> ppid：父进程 id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> cwd()：进程工作目录</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> env：环境变量 比如 NODE_ENV</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> platform：进程运行的操作平台</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> uptime()：当前进程已运行时间</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> memoryUsage()：进程内存使用</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 进程信号：exit、on 发送和接收。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGINT：中断信号被发到进程时发出，比如 ctrl + c。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGTERM：发出终止进程的请求时发出，window 不支持。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGBEAK：Window Ctrl + Break 组合键按下时发出。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGKILL：进程被杀时发出</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGSTOP：进程终止时发出</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 进程事件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> nextTick(cb)：将回调函数推迟到下次事件循环中执行。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> kill(pid, [signal])：结束对应进程并发送一个信号。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exit(code)：退出进程，返回传入值 0 正常、1 故障。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> on(&#x27;exit&#x27;, cb)：监听进程退出，用于报错或释放资源。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> on(&#x27;uncaughtException&#x27;, cb)：监听未捕获的异常。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 标准流</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> stdin：标准输入</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> stdout：标准输出</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> stderr：标准错误输出</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">end</span>(<span class="string">&#x27;hello&#x27;</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>);</span><br><span class="line">　　 process.<span class="title function_">nextTick</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">3000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>,<span class="keyword">function</span>(<span class="params">code</span>)&#123;</span><br><span class="line">    <span class="keyword">switch</span> (code) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">100</span>:</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;process:uncaughtException&#x27;</span>);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">101</span>:</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;process:SIGINT&#x27;</span>);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">102</span>:</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;process:SIGTERM&#x27;</span>);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;process:unknown&#x27;</span>);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;uncaughtException&#x27;</span>,<span class="keyword">function</span>(<span class="params">e</span>)&#123;</span><br><span class="line">    process.<span class="title function_">exit</span>(<span class="number">100</span>);      <span class="comment">// 事件循环中断而直接退出</span></span><br><span class="line">    process.<span class="property">exitCode</span> = <span class="number">0</span>    <span class="comment">// 进程任务执行后自然退出</span></span><br><span class="line">    process.<span class="title function_">kill</span>(process.<span class="property">pid</span>, <span class="string">&#x27;SIGTERM&#x27;</span>);  </span><br><span class="line">&#125;);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;SIGINT&#x27;</span>,<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    process.<span class="title function_">exit</span>(<span class="number">101</span>);</span><br><span class="line">&#125;);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;SIGTERM&#x27;</span>,<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    process.<span class="title function_">exit</span>(<span class="number">102</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">process.<span class="property">stdin</span>.<span class="title function_">setEncoding</span>(<span class="string">&quot;utf8&quot;</span>);    <span class="comment">// 编码默认 Buffer</span></span><br><span class="line">process.<span class="property">stdin</span>.<span class="title function_">on</span>(<span class="params"><span class="string">&quot;readable&quot;</span>, () =&gt; &#123;</span></span><br><span class="line"><span class="params">    <span class="keyword">let</span> chunk = process.stdin.read();</span></span><br><span class="line"><span class="params">    <span class="keyword">if</span> (chunk !== <span class="literal">null</span>) &#123;</span></span><br><span class="line"><span class="params">        chunk = chunk.slice(<span class="number">0</span>, -<span class="number">1</span>)   // 解决回车符导致的问题</span></span><br><span class="line"><span class="params">    &#125;</span></span><br><span class="line"><span class="params">    <span class="keyword">if</span>（chunk !== <span class="string">&#x27;&#x27;</span>) &#123;</span></span><br><span class="line"><span class="params">        process.stdin.emit(<span class="string">&#x27;end&#x27;</span>)    // 触发事件 stdin.end</span></span><br><span class="line"><span class="params">    &#125;</span></span><br><span class="line"><span class="params">&#125;</span>);</span><br><span class="line">process.<span class="property">stdin</span>.<span class="title function_">on</span>(<span class="string">&quot;end&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    process.<span class="property">stdout</span>.<span class="title function_">write</span>(<span class="string">&quot;结束&quot;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> username = <span class="string">&#x27;chuang&#x27;</span></span><br><span class="line">process.<span class="property">stdout</span>.<span class="title function_">write</span>(<span class="string">&quot;请输入用户名:&quot;</span>);</span><br><span class="line">process.<span class="property">stdin</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">input</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (input.<span class="title function_">toString</span>().<span class="title function_">trim</span>() == username)&#123;</span><br><span class="line">        process.<span class="property">stdout</span>.<span class="title function_">write</span>(<span class="string">&#x27;用户名不正确&#x27;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        process.<span class="property">stdout</span>.<span class="title function_">write</span>(<span class="string">&quot;登陆成功&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="多进程架构"><a href="#多进程架构" class="headerlink" title="多进程架构"></a>多进程架构</h2><blockquote>
<p>NodeJS 由于事件驱动性永不阻塞而一般不需要并发执行，但单进程必然无法充分利用 CPU，所以提出了一个主进程、多个子进程的多进程架构。多进程架构之前只能使用 child_process 手动创建子进程并管理，后来引入了开箱即用的模块 cluster。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、child_process：执行命令、利用多进程执行代码</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 创建方式</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> spawn：只是执行命令但没有回调，后面方法基于 spawn。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exec：执行命令并衍生一个 shell 脚本后创建，运行慢。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> execFile：读取可执行文件后会直接创建新进程，运行快。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> fork：只能执行 js 文件而复制出新进程，不支持 shell。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 方式说明</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 每个实例都有 stdout、stdin、stderr 流对象。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exec/execFile 可指定 timeout 超时就被杀死。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> spawn 通过流数据输出结果而适用于执行 npm install  </span></span><br><span class="line"><span class="comment"> * 等耗时任务，fork 复制进程是为了充分利用 CPU 资源，适用于文件</span></span><br><span class="line"><span class="comment"> * 下载等耗时任务，exec/execFile 关注结果而适用于开销小的任务。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 实例事件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> error：无法衍生进程、进程无法 kill、发送消息失败。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exit(code, sign)：子进程通过信号结束或自行退出。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> close(code, sign)：子进程 stdio 流已关闭时。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> message：子进程传递消息时执行 process.send。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> disconnect：父进程手动调用 child.disconnect。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> code 说明</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGINT：终止信号，比如用户按下 CTRL + C 时发出。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGTERM：结束信号，比如命令 kill 缺省时就会产生。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> SIGKILL：强制终止信号，比如进程无法被杀时就会尝试。</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">const</span> cp = <span class="built_in">require</span>(<span class="string">&#x27;child_process&#x27;</span>);</span><br><span class="line">cp.<span class="title function_">spawn</span>(<span class="string">&#x27;node&#x27;</span>, [<span class="string">&#x27;./dir/worker.js&#x27;</span>], &#123; <span class="attr">stdio</span>: <span class="string">&#x27;inherit&#x27;</span> &#125;);</span><br><span class="line">cp.<span class="title function_">exec</span>(<span class="string">&#x27;node worker.sh&#x27;</span>, <span class="function">(<span class="params">err, stdout, stderr</span>) =&gt;</span> &#123; &#125;)</span><br><span class="line">cp.<span class="title function_">execFile</span>(<span class="string">&#x27;node&#x27;</span>, [<span class="string">&#x27;./dir/worker.sh&#x27;</span>], <span class="function">(<span class="params">err, stdout, stderr</span>) =&gt;</span> &#123;&#125;)</span><br><span class="line">cp.<span class="title function_">fork</span>(<span class="string">&#x27;./dir/worker.js&#x27;</span>, &#123; <span class="attr">silent</span>: <span class="literal">true</span> &#125;);  <span class="comment">// 没有回调函数</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 错误监听</span></span><br><span class="line"><span class="title function_">exec</span>(<span class="string">&#x27;ls&#x27;</span>, &#123;<span class="attr">cwd</span>: __dirname + <span class="string">&#x27;/dir&#x27;</span>&#125;, <span class="function">(<span class="params">error, stdout, stderr</span>) =&gt;</span> &#123;&#125;)</span><br><span class="line"><span class="title function_">exec</span>(<span class="string">&#x27;node ./dir/worker.js&#x27;</span>).<span class="property">stderr</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> &#123; &#125;)</span><br><span class="line"><span class="title function_">spawn</span>(<span class="string">&#x27;bad_com&#x27;</span>).<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> &#123; &#125;);    <span class="comment">// 不存在的命令</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 多进程架构</span></span><br><span class="line"><span class="comment">// master.js</span></span><br><span class="line"><span class="keyword">const</span> fork = <span class="built_in">require</span>(<span class="string">&#x27;child_process&#x27;</span>).<span class="property">fork</span>;</span><br><span class="line"><span class="keyword">const</span> cpus = <span class="built_in">require</span>(<span class="string">&#x27;os&#x27;</span>).<span class="title function_">cpus</span>();</span><br><span class="line"><span class="keyword">const</span> server = <span class="built_in">require</span>(<span class="string">&#x27;net&#x27;</span>).<span class="title function_">createServer</span>();</span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">3000</span>);</span><br><span class="line">process.<span class="property">title</span> = <span class="string">&#x27;node-master&#x27;</span></span><br><span class="line"><span class="keyword">const</span> workers = &#123;&#125;;</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">createWorker</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> worker = <span class="title function_">fork</span>(<span class="string">&#x27;worker.js&#x27;</span>)</span><br><span class="line">    <span class="comment">// 收到信号后立即重启新进程</span></span><br><span class="line">    worker.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="keyword">function</span> (<span class="params">message</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (message.<span class="property">act</span> === <span class="string">&#x27;suicide&#x27;</span>) &#123;</span><br><span class="line">            <span class="title function_">createWorker</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// 某个进程终止时重新启动新进程</span></span><br><span class="line">    worker.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="keyword">function</span>(<span class="params">code, signal</span>) &#123;</span><br><span class="line">        <span class="keyword">delete</span> workers[worker.<span class="property">pid</span>];</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// 句柄转发</span></span><br><span class="line">    worker.<span class="title function_">send</span>(<span class="string">&#x27;server&#x27;</span>, server);</span><br><span class="line">    workers[worker.<span class="property">pid</span>] = worker;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; cpus.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="title function_">createWorker</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// kill(2) Ctrl-C、kill(3) Ctrl-\、kill(15) default</span></span><br><span class="line">process.<span class="title function_">once</span>(<span class="string">&#x27;SIGINT&#x27;</span>, close.<span class="title function_">bind</span>(<span class="variable language_">this</span>, <span class="string">&#x27;SIGINT&#x27;</span>));</span><br><span class="line">process.<span class="title function_">once</span>(<span class="string">&#x27;SIGQUIT&#x27;</span>, close.<span class="title function_">bind</span>(<span class="variable language_">this</span>, <span class="string">&#x27;SIGQUIT&#x27;</span>));</span><br><span class="line">process.<span class="title function_">once</span>(<span class="string">&#x27;SIGTERM&#x27;</span>, close.<span class="title function_">bind</span>(<span class="variable language_">this</span>, <span class="string">&#x27;SIGTERM&#x27;</span>));</span><br><span class="line">process.<span class="title function_">once</span>(<span class="string">&#x27;exit&#x27;</span>, close.<span class="title function_">bind</span>(<span class="variable language_">this</span>));</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">close</span> (code) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;进程退出！&#x27;</span>, code);</span><br><span class="line">    <span class="keyword">if</span> (code !== <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> pid <span class="keyword">in</span> workers) &#123;</span><br><span class="line">            workers[pid].<span class="title function_">kill</span>(<span class="string">&#x27;SIGINT&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    process.<span class="title function_">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// worker.js</span></span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123; <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;text/plan&#x27;</span> &#125;);</span><br><span class="line">    res.<span class="title function_">end</span>(<span class="string">&#x27;handled by child, pid is &#x27;</span> + process.<span class="property">pid</span> + <span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;worker exception!&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">let</span> worker;</span><br><span class="line">process.<span class="property">title</span> = <span class="string">&#x27;node-worker&#x27;</span></span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="keyword">function</span> (<span class="params">message, sendHandle</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (message === <span class="string">&#x27;server&#x27;</span>) &#123;</span><br><span class="line">        worker = sendHandle;</span><br><span class="line">        worker.<span class="title function_">on</span>(<span class="string">&#x27;connection&#x27;</span>, <span class="keyword">function</span>(<span class="params">socket</span>) &#123;</span><br><span class="line">            server.<span class="title function_">emit</span>(<span class="string">&#x27;connection&#x27;</span>, socket);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;uncaughtException&#x27;</span>, <span class="keyword">function</span> (<span class="params">err</span>) &#123;</span><br><span class="line">    <span class="comment">// 主动发出信号，避免等待连接断开时无法响应新请求</span></span><br><span class="line">    process.<span class="title function_">send</span>(&#123;<span class="attr">act</span>: <span class="string">&#x27;suicide&#x27;</span>&#125;);</span><br><span class="line">    <span class="comment">// 停止接收新连接</span></span><br><span class="line">    worker.<span class="title function_">close</span>(<span class="function">() =&gt;</span> &#123; process.<span class="title function_">exit</span>(<span class="number">1</span>); &#125;)</span><br><span class="line">    <span class="comment">// 避免长连接请求长时间无法终止，5s 后自动终止</span></span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123; process.<span class="title function_">exit</span>(<span class="number">1</span>); &#125;, <span class="number">5000</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 2、cluster：master 监听端口并将请求转发给 worker 而实现端口共享。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> cluster 属性</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> setttings：配置集群参数对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> isMaster/isWorker：判断是否 主/子 进程</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> worker/workers：当前/所有 worker 对象</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> cluster 方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> fork([env])：创建 worker 进程</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> disconnect([cb])：关闭 worket 进程</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> setupMaster([settings])：设置集群参数</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> cluster 监听</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> fork：worker 创建，本质 child_process.fork</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> online：worker 创建成功</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> listening：worker 开始监听</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> disconnect：worker 断线</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> setup：监听 setupMaster</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exit：worker 退出</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> worker 属性</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> id：进程 ID</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> process: ChildProcess 对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> suicide: disconnect 后判断 worker 是否自杀</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> worker 方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> send(msg, [sendHandle]): master 发送的消息</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> kill([signal=&#x27;SIGTERM&#x27;]): 杀死指定 worker</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> disconnect: 断开 worker 连接并让其自杀</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> worker 监听</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> message: 接收到消息</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> online: 指定 worker 创建成功</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> listening: master 开始监听</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> disconnect: worker 断线</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> exit: worker 退出</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// server.js</span></span><br><span class="line"><span class="keyword">const</span> cluster = <span class="built_in">require</span>(<span class="string">&#x27;cluster&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> numCPUs = <span class="built_in">require</span>(<span class="string">&#x27;os&#x27;</span>).<span class="title function_">cpus</span>().<span class="property">length</span>;</span><br><span class="line">cluster.<span class="title function_">setupMaster</span>(&#123; <span class="attr">exec</span>: <span class="string">&quot;worker.js&quot;</span> &#125;);</span><br><span class="line"><span class="keyword">var</span> cpus = <span class="built_in">require</span>(<span class="string">&#x27;os&#x27;</span>).<span class="title function_">cpus</span>(); </span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; numCPUs; i++) &#123;</span><br><span class="line">    cluster.<span class="title function_">fork</span>();    <span class="comment">// 创建多个工作进程，程序启动多次 worker.js。</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// worker.js：工作进程可以共享任何 TCP 连接，本例共享的是 HTTP 服务器。</span></span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>);</span><br><span class="line">    res.<span class="title function_">end</span>(<span class="string">&#x27;你好世界\n&#x27;</span>);</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">8000</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`工作进程 <span class="subst">$&#123;process.pid&#125;</span> 已启动`</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建 HTTP 服务器</span></span><br><span class="line"><span class="keyword">const</span> cluster = <span class="built_in">require</span>(<span class="string">&#x27;cluster&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> numCPUs = <span class="built_in">require</span>(<span class="string">&#x27;os&#x27;</span>).<span class="title function_">cpus</span>().<span class="property">length</span>;</span><br><span class="line"><span class="keyword">if</span> (cluster.<span class="property">isMaster</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Master <span class="subst">$&#123;process.pid&#125;</span> is running`</span>);</span><br><span class="line">    <span class="keyword">let</span> numWorkers = <span class="number">1</span>;   <span class="comment">// 动态调整子进程数，默认赋值 = numCPUs。</span></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">updateWorkers</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">const</span> workerLen = <span class="title class_">Object</span>.<span class="title function_">keys</span>(cluster.<span class="property">workers</span>).<span class="property">length</span>;</span><br><span class="line">        <span class="keyword">if</span> (numWorkers &gt; workerLen) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Master adding worker <span class="subst">$&#123;workerLen&#125;</span>`</span>);</span><br><span class="line">            cluster.<span class="title function_">fork</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (workerLen &gt; numWorkers) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Master removing worker <span class="subst">$&#123;workerLen - <span class="number">1</span>&#125;</span>`</span>);</span><br><span class="line">            <span class="title class_">Object</span>.<span class="title function_">values</span>(cluster.<span class="property">workers</span>)[<span class="number">0</span>].<span class="title function_">kill</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="built_in">setInterval</span>(updateWorkers, <span class="number">5000</span>);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; numWorkers; i++) &#123;</span><br><span class="line">        cluster.<span class="title function_">fork</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    cluster.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="function">(<span class="params">worker, code, signal</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`worker <span class="subst">$&#123;worker.process.pid&#125;</span> died`</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">        res.<span class="title function_">writeHead</span>(<span class="number">200</span>);</span><br><span class="line">        res.<span class="title function_">end</span>(<span class="string">&#x27;hello world\n&#x27;</span>);</span><br><span class="line">    &#125;).<span class="title function_">listen</span>(<span class="number">8000</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Worker <span class="subst">$&#123;process.pid&#125;</span> started`</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 多进程架构</span></span><br><span class="line"><span class="comment">// master.js</span></span><br><span class="line"><span class="keyword">const</span> cluster = <span class="built_in">require</span>(<span class="string">&quot;cluster&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> cpuLen = <span class="built_in">require</span>(<span class="string">&quot;os&quot;</span>).<span class="title function_">cpus</span>().<span class="property">length</span>;</span><br><span class="line">cluster.<span class="title function_">setupPrimary</span>(&#123; <span class="attr">exec</span>: <span class="string">&#x27;worker.js&#x27;</span> &#125;);   <span class="comment">// 修改默认 fork</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; cpuLen; i++) &#123;</span><br><span class="line">    cluster.<span class="title function_">fork</span>();</span><br><span class="line">&#125;;</span><br><span class="line">cluster.<span class="title function_">on</span>(<span class="string">&#x27;listening&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`listenning on: <span class="subst">$&#123;data.id&#125;</span>--<span class="subst">$&#123;data.process.pid&#125;</span>`</span>);</span><br><span class="line">&#125;);</span><br><span class="line">cluster.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="function">(<span class="params">data, code, signal</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;data.id&#125;</span> kill $[code], signal: <span class="subst">$&#123;signal&#125;</span>`</span>);</span><br><span class="line">    cluster.<span class="title function_">fork</span>();</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// worker.js</span></span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&quot;http&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123; <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;text/plain&quot;</span> &#125;);</span><br><span class="line">res.<span class="title function_">end</span>(<span class="string">&quot;Hello,World!&quot;</span> + process.<span class="property">pid</span>);</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;throw exception&#x27;</span>);</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">1337</span>);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;uncaughtException&#x27;</span>, <span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">    server.<span class="title function_">close</span>(<span class="function"><span class="params">data</span> =&gt;</span> &#123; process.<span class="title function_">exit</span>(<span class="number">1</span>); &#125;)</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123; process.<span class="title function_">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;, <span class="number">5000</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="多进程通信"><a href="#多进程通信" class="headerlink" title="多进程通信"></a>多进程通信</h2><blockquote>
<p>多线程之间共享地址空间和数据空间，所以一个线程的数据可以直接提供给其他线程使用，进程间的独立性则需要通过操作系统。<code>不同电脑的进程</code>可通过 TCP HTTP、<code>一台电脑的进程和子进程</code>可通过内置通道 IPC、<code>一台电脑的进程和无关进程</code>可通过自定义管道。注意内置管道 pipe 只能实现父子进程数据的单向流动，命名管道 FIFO 则可以实现无关进程的通信，管道的本质是让不同进程可以写入和读取一次数据并且读取后就会自动清空的一块内核缓冲区。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、IPC 内置通道： child_process 父子</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> pipe 管道：spawn 数据从输入流传入输出流</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> message 消息：send 发送、message 监听</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> stdio 创建的流：write 发送、data 监听</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="comment">// pipe 管道：cat 输出流传输到 wc 输入流，相当于执行 cat ./a.js | wc -l</span></span><br><span class="line"><span class="keyword">const</span> &#123; spawn &#125; = <span class="built_in">require</span>(<span class="string">&#x27;child_process&#x27;</span>); </span><br><span class="line"><span class="keyword">let</span> cat = <span class="title function_">spawn</span>(<span class="string">&#x27;cat&#x27;</span>, [<span class="string">&#x27;./a.js&#x27;</span>])</span><br><span class="line"><span class="keyword">const</span> wc = <span class="title function_">spawn</span>(<span class="string">&#x27;wc&#x27;</span>, [<span class="string">&#x27;-l&#x27;</span>]);  </span><br><span class="line">cat.<span class="property">stdout</span>.<span class="title function_">pipe</span>(wc.<span class="property">stdin</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// fork message 监听</span></span><br><span class="line"><span class="keyword">const</span> &#123;fork, spawn&#125; = <span class="built_in">require</span>(<span class="string">&quot;child_process&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> child = <span class="title function_">fork</span>(<span class="string">&#x27;./child.js&#x27;</span>, [], &#123; <span class="attr">stdio</span>: <span class="string">&quot;inherit&quot;</span> &#125;);</span><br><span class="line"><span class="keyword">const</span> child = <span class="title function_">spawn</span>(<span class="string">&#x27;node&#x27;</span>, [<span class="string">&#x27;./child.js&#x27;</span>], &#123;</span><br><span class="line">    <span class="attr">stdio</span>: [<span class="string">&#x27;pipe&#x27;</span>, <span class="string">&#x27;pipe&#x27;</span>, <span class="string">&#x27;pipe&#x27;</span>, <span class="string">&#x27;ipc&#x27;</span>] </span><br><span class="line">&#125;); </span><br><span class="line">child.<span class="title function_">on</span>(<span class="string">&quot;message&quot;</span>, <span class="function">(<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;子进程发送的消息:&quot;</span>, message)</span><br><span class="line">    child.<span class="title function_">send</span>(<span class="string">&quot;hi&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">process.<span class="property">title</span> = <span class="string">&#x27;worker 子进程&#x27;</span></span><br><span class="line">process.<span class="title function_">send</span>(<span class="string">&quot;hello&quot;</span>)</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&quot;message&quot;</span>, <span class="function">(<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;主进程发送的消息:&quot;</span>, message);</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Stream 监听：parent.js、child.js</span></span><br><span class="line"><span class="keyword">let</span> worker = child_process.<span class="title function_">spawn</span>(<span class="string">&#x27;node&#x27;</span>, [<span class="string">&#x27;child.js&#x27;</span>], &#123;</span><br><span class="line">    <span class="attr">stdio</span>: [<span class="string">&#x27;ignore&#x27;</span>, <span class="string">&#x27;ignore&#x27;</span>, process.<span class="property">stderr</span>, <span class="string">&#x27;pipe&#x27;</span>]</span><br><span class="line">&#125;);</span><br><span class="line">worker.<span class="property">stdio</span>[<span class="number">3</span>].<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">chunk</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(chunk.<span class="title function_">toString</span>());</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> ws = fs.<span class="title function_">createWriteStream</span>(<span class="literal">null</span>, &#123; <span class="attr">fd</span>: <span class="number">3</span> &#125;);</span><br><span class="line">ws.<span class="title function_">write</span>(<span class="string">&#x27;Hello world&#x27;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、信号通信：用户动作或 kill 等方法向当前进程发送通知</span></span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>,<span class="keyword">function</span>(<span class="params">code</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(code);</span><br><span class="line">&#125;);</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;SIGINT&#x27;</span>,<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    process.<span class="title function_">exit</span>(<span class="number">101</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 3、TCP 套接字：server.js、client.js</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node server.js：connected：receive: hello、send: hello</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node client.js：connect、send: hello、receive: hello</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">const</span> net = <span class="built_in">require</span>(<span class="string">&#x27;net&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = net.<span class="title function_">createServer</span>(<span class="function"><span class="params">socket</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;connected&#x27;</span>)</span><br><span class="line">    socket.<span class="title function_">on</span>(<span class="string">&#x27;close&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;disconnected&#x27;</span>))</span><br><span class="line">    socket.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err.<span class="property">message</span>))</span><br><span class="line">    socket.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`receive: <span class="subst">$&#123;data&#125;</span>`</span>)</span><br><span class="line">        socket.<span class="title function_">write</span>(data)</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`send: <span class="subst">$&#123;data&#125;</span>`</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">8888</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> net = <span class="built_in">require</span>(<span class="string">&#x27;net&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> client = net.<span class="title function_">connect</span>(<span class="number">8888</span>, <span class="string">&#x27;192.168.10.105&#x27;</span>)</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;connect&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;connected&#x27;</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`receive: <span class="subst">$&#123;data&#125;</span>`</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;disconnected&#x27;</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err.<span class="property">message</span>))</span><br><span class="line"><span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> msg = <span class="string">&#x27;hello&#x27;</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`send: <span class="subst">$&#123;msg&#125;</span>`</span>)</span><br><span class="line">    client.<span class="title function_">write</span>(msg)</span><br><span class="line">&#125;, <span class="number">3000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 4、HTTP 协议：server.js、client.js</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node server.js：url /hello</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node client.js：statusCode: 200、hello</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =&gt;</span> res.<span class="title function_">end</span>(req.<span class="property">url</span>)).<span class="title function_">listen</span>(<span class="number">8888</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> options = &#123;</span><br><span class="line">    <span class="attr">hostname</span>: <span class="string">&#x27;192.168.10.105&#x27;</span>,</span><br><span class="line">    <span class="attr">port</span>: <span class="number">8888</span>,</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;/hello&#x27;</span>,</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;GET&#x27;</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> req = http.<span class="title function_">request</span>(options, <span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`statusCode: <span class="subst">$&#123;res.statusCode&#125;</span>`</span>)</span><br><span class="line">    res.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">d</span> =&gt;</span> process.<span class="property">stdout</span>.<span class="title function_">write</span>(d))</span><br><span class="line">&#125;)</span><br><span class="line">req.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">error</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(error))</span><br><span class="line">req.<span class="title function_">end</span>()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 5、自定义管道：server.js、client.js</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node server.js：connected、receive: hello、send: hello</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> node client.js：connected、send: hello、receive: hello</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Window 使用命名管道、unix 使用 unix domain socket</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> net = <span class="built_in">require</span>(<span class="string">&#x27;net&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> pipeFile = process.<span class="property">platform</span> === <span class="string">&#x27;win32&#x27;</span> ? </span><br><span class="line"><span class="string">&#x27;\\.\pipe\mypip&#x27;</span> : <span class="string">&#x27;/tmp/unix.sock&#x27;</span></span><br><span class="line"><span class="keyword">const</span> server = net.<span class="title function_">createServer</span>(<span class="function"><span class="params">connection</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;socket connected.&#x27;</span>)</span><br><span class="line">    connection.<span class="title function_">on</span>(<span class="string">&#x27;close&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;disconnected&#x27;</span>))</span><br><span class="line">    connection.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`receive: <span class="subst">$&#123;data&#125;</span>`</span>)</span><br><span class="line">        connection.<span class="title function_">write</span>(data)</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`send: <span class="subst">$&#123;data&#125;</span>`</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    connection.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err.<span class="property">message</span>))</span><br><span class="line">&#125;)</span><br><span class="line">fs.<span class="title function_">unlinkSync</span>(pipeFile)</span><br><span class="line">server.<span class="title function_">listen</span>(pipeFile)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> net = <span class="built_in">require</span>(<span class="string">&#x27;net&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> pipeFile = process.<span class="property">platform</span> === <span class="string">&#x27;win32&#x27;</span> ? </span><br><span class="line"><span class="string">&#x27;\\.\pipe\mypip&#x27;</span> : <span class="string">&#x27;/tmp/unix.sock&#x27;</span></span><br><span class="line"><span class="keyword">const</span> client = net.<span class="title function_">connect</span>(pipeFile)</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;connect&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;connected&#x27;</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`receive: <span class="subst">$&#123;data&#125;</span>`</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;disconnected&#x27;</span>))</span><br><span class="line">client.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(err.<span class="property">message</span>))</span><br><span class="line"><span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> msg = <span class="string">&#x27;hello&#x27;</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`send: <span class="subst">$&#123;msg&#125;</span>`</span>)</span><br><span class="line">    client.<span class="title function_">write</span>(msg)</span><br><span class="line">&#125;, <span class="number">3000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 6、共享内存</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 主进程创建 SharedArrayBuffer 对象并通过 IPC 发到子进程。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 子进程通过 Atomics 模块提供的原子操作函数访问和修改内存。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> cluster = <span class="built_in">require</span>(<span class="string">&#x27;cluster&#x27;</span>);</span><br><span class="line"><span class="keyword">if</span> (cluster.<span class="property">isMaster</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> sharedBuffer = <span class="keyword">new</span> <span class="title class_">SharedArrayBuffer</span>(<span class="number">1024</span>);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> id <span class="keyword">in</span> cluster.<span class="property">workers</span>) &#123;</span><br><span class="line">        [id].<span class="title function_">send</span>(sharedBuffer);</span><br><span class="line">    &#125;</span><br><span class="line">    cluster.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function">(<span class="params">worker, message</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`worker: <span class="subst">$&#123;worker.id&#125;</span>:`</span>, message);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">        cluster.<span class="title function_">fork</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    process.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">message</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`master message:`</span>, message);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> &#123; parentPort &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Atomics</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line">parentPort.<span class="title function_">once</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function">(<span class="params">sharedBuffer</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> sharedArray = <span class="keyword">new</span> <span class="title class_">Int32Array</span>(sharedBuffer);</span><br><span class="line">    <span class="title class_">Atomics</span>.<span class="title function_">store</span>(sharedArray, <span class="number">0</span>, <span class="number">42</span>);</span><br><span class="line">    parentPort.<span class="title function_">postMessage</span>(<span class="string">&#x27;worker send&#x27;</span>);</span><br><span class="line">    parentPort.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">message</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`master message:`</span>, message);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br><span class="line">  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 7、消息队列：RabbitMQ、Kafka、Redis 等常用于分布式系统的库。</span></span><br></pre></td></tr></table></figure>


<h2 id="多线程架构"><a href="#多线程架构" class="headerlink" title="多线程架构"></a>多线程架构</h2><blockquote>
<p>cluster 子进程之间无法共享内存、通信必须使用 JSON 的问题，worker_thread 模块则允许在一个 Node 实例中运行有多个线程的一个进程，相比创建多进程更轻量而且可共享内存。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> worker_thread 模块 </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> threadId: 线程 ID</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> isMainThread: 是否主线程</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Worker: 主线程中创建子线程</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> MessagePort: 用于跨线程通信的句柄</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> MessageChannel: 用于创建通信通道</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> parentPort: 父进程 MessagePort 对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> workerData: 主进程中向子进程传递的数据</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 线程通信</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> worker.postMessage：主线程中使用</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> parentPort.postMessage：工作线程</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// 主线程脚本文件</span></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Worker</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> worker1 = <span class="keyword">new</span> <span class="title class_">Worker</span>(<span class="string">&#x27;./worker1.js&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> worker2 = <span class="keyword">new</span> <span class="title class_">Worker</span>(<span class="string">&#x27;./worker2.js&#x27;</span>);</span><br><span class="line">worker1.<span class="title function_">postMessage</span>(<span class="string">&#x27;master&#x27;</span>)</span><br><span class="line">worker1.<span class="title function_">on</span>(<span class="string">&#x27;exit&#x27;</span>, <span class="function"><span class="params">code</span> =&gt;</span> &#123; </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`worker1 stopped with <span class="subst">$&#123;code&#125;</span>`</span>); </span><br><span class="line">&#125;);</span><br><span class="line">worker1.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line">&#125;)</span><br><span class="line">worker2.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// worker1.js</span></span><br><span class="line"><span class="keyword">const</span> &#123; parentPort, workerData &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line">parentPort.<span class="title function_">postMessage</span>(<span class="string">&#x27;worker1: &#x27;</span> + workerData)</span><br><span class="line">parentPort.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 工作线程间通信：run.js、worker1.js</span></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">MessageChannel</span>, <span class="title class_">Worker</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> subChannel = <span class="keyword">new</span> <span class="title class_">MessageChannel</span>();</span><br><span class="line"><span class="keyword">const</span> worker1 = <span class="keyword">new</span> <span class="title class_">Worker</span>(<span class="string">&#x27;./worker1.js&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> worker2 = <span class="keyword">new</span> <span class="title class_">Worker</span>(<span class="string">&#x27;./worker2.js&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> &#123; port1, port2 &#125; = subChannel;</span><br><span class="line">worker1.<span class="title function_">postMessage</span>(&#123; <span class="attr">hereIsYourPort</span>: port1 &#125;, [port1]);</span><br><span class="line">worker2.<span class="title function_">postMessage</span>(&#123; <span class="attr">hereIsYourPort2</span>: port2 &#125;, [port2]);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">const</span> &#123; parentPort &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line">parentPort.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">    msg.<span class="property">hereIsYourPort</span>.<span class="title function_">postMessage</span>(<span class="string">&#x27;i am worker1&#x27;</span>)</span><br><span class="line">    msg.<span class="property">hereIsYourPort</span>.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> &#123; parentPort &#125; = <span class="built_in">require</span>(<span class="string">&#x27;worker_threads&#x27;</span>);</span><br><span class="line">parentPort.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">    msg.<span class="property">hereIsYourPort2</span>.<span class="title function_">postMessage</span>(<span class="string">&#x27;i am worker2&#x27;</span>)</span><br><span class="line">    msg.<span class="property">hereIsYourPort2</span>.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">msg</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(msg)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h1 id="四、应用场景"><a href="#四、应用场景" class="headerlink" title="四、应用场景"></a>四、应用场景</h1><h2 id="搭建服务器"><a href="#搭建服务器" class="headerlink" title="搭建服务器"></a>搭建服务器</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、通过插件：http-server、live-server</span></span><br><span class="line">npm install http-server -g</span><br><span class="line">cd progect      <span class="comment">// 进入项目目录</span></span><br><span class="line">http-server     <span class="comment">// 开启服务</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、通过 NodeJS：命令行第三个参数为相对当前 server.js 的目录名称</span></span><br><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">&#x27;url&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> dir, arg = process.<span class="property">argv</span>[<span class="number">2</span>] || <span class="string">&#x27;&#x27;</span>; </span><br><span class="line"></span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> pathname = **dirname + url.<span class="title function_">parse</span>(req.<span class="property">url</span>).<span class="property">pathname</span>;</span><br><span class="line">    dir = dir ? dir : pathname; </span><br><span class="line">    <span class="comment">// 替换文件静态路径</span></span><br><span class="line">    pathname = dir ? pathname.<span class="title function_">replace</span>(dir, dir + arg + <span class="string">&#x27;/&#x27;</span>) : pathname; </span><br><span class="line">    <span class="keyword">if</span> (path.<span class="title function_">extname</span>(pathname) == <span class="string">&quot;&quot;</span>) &#123;</span><br><span class="line">        pathname += <span class="string">&quot;/&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (pathname.<span class="title function_">charAt</span>(pathname.<span class="property">length</span> - <span class="number">1</span>) == <span class="string">&quot;/&quot;</span>) &#123;</span><br><span class="line">        <span class="comment">// 入口文件，此处默认 index.html</span></span><br><span class="line">        pathname += <span class="string">&quot;index.html&quot;</span>; </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    fs.<span class="title function_">exists</span>(pathname, <span class="keyword">function</span> (<span class="params">exists</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!exists) &#123;</span><br><span class="line">            res.<span class="title function_">writeHead</span>(<span class="number">404</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;text/html&quot;</span>&#125;);</span><br><span class="line">            res.<span class="title function_">end</span>(<span class="string">&quot;Not Found&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> _pathname = path.<span class="title function_">extname</span>(pathname)</span><br><span class="line">        <span class="keyword">switch</span> (_pathname) &#123;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.html&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;text/html&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.js&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;text/javascript&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.css&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;text/css&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.gif&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;image/gif&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.jpg&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;image/png&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">&quot;.png&quot;</span>:</span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;image/png&quot;</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">          <span class="attr">default</span>:</span><br><span class="line">              <span class="keyword">let</span> <span class="title class_">ContentType</span> = <span class="string">&#x27;application/octet-stream&#x27;</span></span><br><span class="line">              res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="title class_">ContentType</span>&#125;);</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        fs.<span class="title function_">readFile</span>(pathname, <span class="keyword">function</span> (<span class="params">err, data</span>) &#123;</span><br><span class="line">            res.<span class="title function_">end</span>(data);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">9090</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1:9090/&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h2 id="连接-mysql"><a href="#连接-mysql" class="headerlink" title="连接 mysql"></a>连接 mysql</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、直接连接：npm install mysql node-mysql -g  </span></span><br><span class="line"><span class="keyword">let</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">let</span> mysql = <span class="built_in">require</span>(<span class="string">&quot;mysql&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> connection = mysql.<span class="title function_">createConnection</span>(&#123;</span><br><span class="line">    <span class="attr">host</span>: <span class="string">&quot;127.0.0.1&quot;</span>,      <span class="comment">// 主机</span></span><br><span class="line">    <span class="attr">user</span>: <span class="string">&quot;root&quot;</span>,           <span class="comment">// 用户名</span></span><br><span class="line">    <span class="attr">password</span>: <span class="string">&quot;xxxxx&quot;</span>,      <span class="comment">// 用户密码</span></span><br><span class="line">    <span class="attr">port</span>: <span class="string">&quot;3306&quot;</span>,           <span class="comment">// 端口号</span></span><br><span class="line">    <span class="attr">database</span>: <span class="string">&quot;mysql&quot;</span>       <span class="comment">// 数据库名</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 连接数据库</span></span><br><span class="line">connection.<span class="title function_">connect</span>(<span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`mysql connect fail: <span class="subst">$&#123;err&#125;</span>!`</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;mysql connect success!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 执行查询</span></span><br><span class="line"><span class="keyword">let</span> str = <span class="string">&quot;&quot;</span>;</span><br><span class="line"><span class="keyword">let</span> sqlQuery = <span class="string">&quot;select * from students&quot;</span>;</span><br><span class="line">connection.<span class="title function_">query</span>(sqlQuery, <span class="keyword">function</span>(<span class="params">err, result</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`SQL error: <span class="subst">$&#123;err&#125;</span>!`</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        str = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// 返回数据</span></span><br><span class="line">http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">end</span>(str)</span><br><span class="line">&#125;).<span class="title function_">listen</span>(<span class="number">3000</span>);</span><br><span class="line"><span class="comment">// 关闭连接</span></span><br><span class="line">connection.<span class="title function_">end</span>(<span class="keyword">function</span>(<span class="params">err</span>)&#123;  </span><br><span class="line">    <span class="keyword">if</span> (err) &#123; </span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="title function_">toString</span>());</span><br><span class="line">        <span class="keyword">return</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;[connection end] succeed!&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、通过连接池：连接池负责分配、管理和释放数据库连接，重复使用时不会新建</span></span><br><span class="line"><span class="keyword">let</span> mysql = <span class="built_in">require</span>(<span class="string">&#x27;mysql&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> pool = mysql.<span class="title function_">createPool</span>(&#123;</span><br><span class="line">    <span class="attr">host</span>: <span class="string">&quot;127.0.0.1&quot;</span>,   <span class="comment">// 主机</span></span><br><span class="line">    <span class="attr">user</span>: <span class="string">&quot;root&quot;</span>,        <span class="comment">// 用户名</span></span><br><span class="line">    <span class="attr">password</span>: <span class="string">&quot;xxxxx&quot;</span>,   <span class="comment">// 用户密码</span></span><br><span class="line">    <span class="attr">port</span>: <span class="string">&quot;3306&quot;</span>,        <span class="comment">// 端口号</span></span><br><span class="line">    <span class="attr">database</span>: <span class="string">&quot;mysql&quot;</span>    <span class="comment">// 数据库名</span></span><br><span class="line">&#125;)</span><br><span class="line">pool.<span class="title function_">getConnection</span>(<span class="keyword">function</span>(<span class="params">err, connection</span>) &#123;</span><br><span class="line">    connection.<span class="title function_">query</span>(<span class="string">&#x27;select * from students&#x27;</span>, [], </span><br><span class="line">    <span class="keyword">function</span>(<span class="params">err, result</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Error: &quot;</span> + err.<span class="property">message</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        connection.<span class="title function_">release</span>();</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h2 id="上传文件"><a href="#上传文件" class="headerlink" title="上传文件"></a>上传文件</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@title</span> server.js</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> 命令说明：dest 定义上传目录、array 限制上传类型</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> 安装依赖：npm install multer body-parser -S</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@param</span> 运行文件：node server.js</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&quot;fs&quot;</span>);</span><br><span class="line"><span class="keyword">var</span> bodyParser = <span class="built_in">require</span>(<span class="string">&#x27;body-parser&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> multer  = <span class="built_in">require</span>(<span class="string">&#x27;multer&#x27;</span>);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(<span class="string">&#x27;public&#x27;</span>));</span><br><span class="line">app.<span class="title function_">use</span>(bodyParser.<span class="title function_">urlencoded</span>(&#123; <span class="attr">extended</span>: <span class="literal">false</span> &#125;));</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">multer</span>(&#123; <span class="attr">dest</span>: <span class="string">&#x27;./uploads&#x27;</span>&#125;).<span class="title function_">array</span>(<span class="string">&#x27;image&#x27;</span>));</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    res.<span class="title function_">sendFile</span>( **dirname + <span class="string">&quot;/&quot;</span> + <span class="string">&quot;index.html&quot;</span> );</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/file_upload&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> filename = req.<span class="property">files</span>[<span class="number">0</span>].<span class="property">originalname</span></span><br><span class="line">    <span class="keyword">var</span> des_file = **dirname + <span class="string">&quot;/&quot;</span> + filename;</span><br><span class="line">    fs.<span class="title function_">readFile</span>(req.<span class="property">files</span>[<span class="number">0</span>].<span class="property">path</span>, <span class="keyword">function</span> (<span class="params">err, data</span>) &#123;</span><br><span class="line">        fs.<span class="title function_">writeFile</span>(des_file, data, <span class="keyword">function</span> (<span class="params">err</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (err) &#123;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            &#125;</span><br><span class="line">            res.<span class="title function_">end</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123; filename&#125;));</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;localhost:3000&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.html</span></span><br><span class="line">&lt;form action=<span class="string">&quot;/file_upload&quot;</span> method=<span class="string">&quot;POST&quot;</span> enctype=<span class="string">&quot;multipart/form-data&quot;</span>&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;file&quot;</span> <span class="attr">name</span>=<span class="string">&quot;image&quot;</span> /&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;上传文件&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span></span><br></pre></td></tr></table></figure>


<h2 id="WebSocket"><a href="#WebSocket" class="headerlink" title="WebSocket"></a>WebSocket</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line">========================= 通过 ws 模块 ========================</span><br><span class="line"><span class="comment">// 客户端 readyState：0 正在连接、1 成功、2：正在关闭、3 关闭</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable language_">window</span>.<span class="property">WebSocket</span> == <span class="literal">undefined</span>) <span class="keyword">return</span></span><br><span class="line"><span class="keyword">var</span> connection = <span class="keyword">new</span> <span class="title class_">WebSocket</span>(<span class="string">&#x27;ws://localhost:6060&#x27;</span>); </span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(connection.<span class="property">readyState</span>);</span><br><span class="line">connection.<span class="property">onopen</span> = <span class="function">(<span class="params">event</span>) =&gt;</span> &#123;</span><br><span class="line">    connection.<span class="title function_">send</span>(<span class="string">&#x27;client message&#x27;</span>); </span><br><span class="line">&#125;;  </span><br><span class="line">connection.<span class="property">onmessage</span> = <span class="function">(<span class="params">event</span>) =&gt;</span> &#123;   </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(event);  </span><br><span class="line">&#125;; </span><br><span class="line">connection.<span class="property">onclose</span> = <span class="function">() =&gt;</span> &#123;   </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Closed&quot;</span>);  </span><br><span class="line">&#125;;</span><br><span class="line">connection.<span class="property">onerror</span> = <span class="function">(<span class="params">event</span>) =&gt;</span> &#123;   </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Error: &quot;</span> + event.<span class="property">data</span>);  </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 服务器 server.js：cnpm i ws -S</span></span><br><span class="line"><span class="keyword">const</span> server = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>).<span class="title function_">createServer</span>();</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">WebSocketServer</span> = <span class="built_in">require</span>(<span class="string">&#x27;ws&#x27;</span>).<span class="property">Server</span>;</span><br><span class="line"><span class="keyword">const</span> wss = <span class="keyword">new</span> <span class="title class_">WebSocketServer</span>(&#123; <span class="attr">server</span>: server &#125;);</span><br><span class="line"><span class="keyword">const</span> app = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)();</span><br><span class="line">app.<span class="title function_">use</span>(<span class="keyword">function</span> (<span class="params">req, res</span>) &#123; </span><br><span class="line">    res.<span class="title function_">send</span>(&#123; <span class="attr">msg</span>: <span class="string">&quot;hello&quot;</span> &#125;);</span><br><span class="line">&#125;);</span><br><span class="line">wss.<span class="title function_">on</span>(<span class="string">&#x27;connection&#x27;</span>, <span class="keyword">function</span> <span class="title function_">connection</span>(<span class="params">ws</span>) &#123; </span><br><span class="line">    ws.<span class="title function_">on</span>(<span class="string">&#x27;message&#x27;</span>, <span class="keyword">function</span> <span class="title function_">incoming</span>(<span class="params">message</span>) &#123; </span><br><span class="line">        <span class="comment">// %s 字符串、%d 整数、%f 浮点数 </span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;received: %s&#x27;</span>, message);</span><br><span class="line">    &#125;);</span><br><span class="line">    ws.<span class="title function_">send</span>(<span class="string">&#x27;something&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>, app);</span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123; </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;http://localhost:&#x27;</span> + server.<span class="title function_">address</span>().<span class="property">port</span>) </span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">========================= 通过 socket.<span class="property">io</span> ========================</span><br><span class="line">cnpm i socket.<span class="property">io</span> -S</span><br><span class="line"></span><br><span class="line"><span class="comment">// 客户端</span></span><br><span class="line"><span class="keyword">var</span> socket = <span class="built_in">require</span>(<span class="string">&#x27;socket.io&#x27;</span>).<span class="title function_">connect</span>(<span class="string">&#x27;http://localhost:8080&#x27;</span>)  </span><br><span class="line">socket.<span class="title function_">on</span>(<span class="string">&#x27;news&#x27;</span>, <span class="keyword">function</span> (<span class="params">data</span>) &#123;   </span><br><span class="line">    socket.<span class="title function_">emit</span>(<span class="string">&#x27;event&#x27;</span>, &#123; <span class="attr">my</span>: <span class="string">&#x27;data&#x27;</span> &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 服务器 server.js</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>).<span class="title function_">createServer</span>(handler).<span class="title function_">listen</span>(<span class="number">8080</span>);</span><br><span class="line"><span class="keyword">const</span> io = <span class="built_in">require</span>(<span class="string">&#x27;socket.io&#x27;</span>).<span class="title function_">listen</span>(app);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">handler</span> (req, res) &#123;</span><br><span class="line">    fs.<span class="title function_">readFile</span>(**dirname + <span class="string">&#x27;/index.html&#x27;</span>,<span class="keyword">function</span> (<span class="params">err, data</span>) &#123;  </span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">            res.<span class="title function_">writeHead</span>(<span class="number">500</span>);</span><br><span class="line">            <span class="keyword">return</span> res.<span class="title function_">end</span>(<span class="string">&#x27;Error loading index.html&#x27;</span>);</span><br><span class="line">        &#125;    </span><br><span class="line">        res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;text/html&#x27;</span>&#125;);    </span><br><span class="line">        res.<span class="title function_">end</span>(data);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line">io.<span class="property">sockets</span>.<span class="title function_">on</span>(<span class="string">&#x27;connection&#x27;</span>, <span class="keyword">function</span> (<span class="params">socket</span>) &#123;</span><br><span class="line">    socket.<span class="title function_">emit</span>(<span class="string">&#x27;news&#x27;</span>, &#123; <span class="attr">hello</span>: <span class="string">&#x27;world&#x27;</span> &#125;);</span><br><span class="line">    socket.<span class="title function_">on</span>(<span class="string">&#x27;my other event&#x27;</span>, <span class="keyword">function</span> (<span class="params">data</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h2 id="解决跨域"><a href="#解决跨域" class="headerlink" title="解决跨域"></a>解决跨域</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">cnpm install cors --save</span><br><span class="line"></span><br><span class="line"><span class="comment">// app.js 加入代码</span></span><br><span class="line"><span class="keyword">var</span> cors = <span class="built_in">require</span>(<span class="string">&#x27;cors&#x27;</span>);</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cors</span>(&#123;</span><br><span class="line">    <span class="attr">origin</span>:[<span class="string">&#x27;http://localhost:8080&#x27;</span>],  <span class="comment">//指定接收的地址</span></span><br><span class="line">    <span class="attr">methods</span>:[<span class="string">&#x27;GET&#x27;</span>,<span class="string">&#x27;POST&#x27;</span>],            <span class="comment">// 指定接收的请求类型</span></span><br><span class="line">    <span class="attr">alloweHeaders</span>:[<span class="string">&#x27;Content-Type&#x27;</span>, <span class="string">&#x27;Authorization&#x27;</span>]  <span class="comment">// 指定 header</span></span><br><span class="line">&#125;))</span><br></pre></td></tr></table></figure>

<h2 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 错误写法：不建议手动包装每个控制器函数。</span></span><br><span class="line"><span class="built_in">exports</span>.<span class="property">login</span> = <span class="keyword">async</span> (req, res, next) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// logic here</span></span><br><span class="line">    &#125; <span class="keyword">catch</span>(error) &#123;</span><br><span class="line">        res.<span class="title function_">status</span>(<span class="number">400</span>).<span class="title function_">json</span>(&#123; <span class="attr">message</span>: error.<span class="property">message</span>&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用自定义函数，将错误传递到下个函数并由全局错误处理程序处理。</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">tryCatchFn</span> = (<span class="params">fn</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function">(<span class="params">req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">fn</span>(req, res, next).<span class="title function_">catch</span>(next);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">exports</span>.<span class="property">login</span> = <span class="title function_">tryCatchFn</span>(<span class="keyword">async</span> (req, res, next) =&gt; &#123;</span><br><span class="line"></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 全局错误处理</span></span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">err, req, res, next</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">status</span>(err.<span class="property">statusCode</span> || <span class="number">500</span>).<span class="title function_">send</span>(err.<span class="property">message</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;uncaughtException&#x27;</span>, <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&quot;所有未捕获的异常: &quot;</span>, err)</span><br><span class="line">&#125;)</span><br><span class="line">process.<span class="title function_">on</span>(<span class="string">&#x27;unhandledRejection&#x27;</span>, <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&quot;所有未处理的 Promise 拒绝: &quot;</span>, err)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


<h2 id="中间件"><a href="#中间件" class="headerlink" title="中间件"></a>中间件</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> route = express.<span class="title class_">Router</span>();</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">isAuthenticated</span> = (<span class="params">req, res, next</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (req.<span class="property">user</span>) &#123;</span><br><span class="line">        <span class="title function_">next</span>();  <span class="comment">// 用户已登录允许访问，否则重新登录</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 错误写法：不要将中间件添加到每个路由</span></span><br><span class="line">route.<span class="title function_">get</span>(<span class="string">&#x27;/products&#x27;</span>, isAuthenticated, getProductList);</span><br><span class="line">route.<span class="title function_">get</span>(<span class="string">&#x27;/product/:id&#x27;</span>, isAuthenticated, getProductById)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过 use 方法添加到路由列表的顶部，下面的路由会自动通过中间件</span></span><br><span class="line">route.<span class="title function_">use</span>(isAuthenticated);</span><br><span class="line">route.<span class="title function_">get</span>(<span class="string">&#x27;/products&#x27;</span>, getProductList);</span><br><span class="line">route.<span class="title function_">get</span>(<span class="string">&#x27;/product/:id&#x27;</span>, getProductById);</span><br></pre></td></tr></table></figure>


<h1 id="五、性能优化"><a href="#五、性能优化" class="headerlink" title="五、性能优化"></a>五、性能优化</h1><h2 id="性能测试"><a href="#性能测试" class="headerlink" title="性能测试"></a>性能测试</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 压测工具 ab</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -c：设定并发数，默认 1</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -n：设定压测的请求总数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -t：设定压测的时长，单位秒</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -p：设定 POST 文件路径，注意设定匹配的 -T 参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -T：设定 POST/PUT 数据格式，默认 text/plain</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -V：查看版本信息</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> -w：以 Html 表格形式输出</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line">ab -c200 -n1600 <span class="attr">http</span>:<span class="comment">//127.0.0.1:3000/index</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 性能指标</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 吞吐量：每秒实际通过某网络的数据量，实际速率。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 带宽：每秒网络所能承载的最大数据量，最大速率。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> QPS：每秒查询率，服务器每秒能够响应的查询次数。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> top 命令：监控负载量、CPU占用率、内存占用率。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> iostat 命令：监控磁盘的读写速度、传输率等。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="title class_">Complete</span> <span class="attr">requests</span>:   <span class="number">1600</span>                         <span class="comment">// 请求完成成功数</span></span><br><span class="line"><span class="title class_">Failed</span> <span class="attr">requests</span>:     <span class="number">0</span>                            <span class="comment">// 请求完成失败数</span></span><br><span class="line"><span class="title class_">Total</span> <span class="attr">transferred</span>:   <span class="number">8142400</span> bytes               <span class="comment">// 测试传输的总数据</span></span><br><span class="line"><span class="variable constant_">HTML</span> <span class="attr">transferred</span>:    <span class="number">7985600</span> bytes</span><br><span class="line"><span class="title class_">Requests</span> per <span class="attr">second</span>: <span class="number">2188.47</span> [#/sec] (mean)  <span class="comment">// QPS 每秒能处理的请求</span></span><br><span class="line"><span class="title class_">Time</span> per <span class="attr">request</span>:    <span class="number">91.388</span> [ms] (mean)     <span class="comment">// 每次请求花费的平均时常</span></span><br><span class="line"><span class="title class_">Time</span> per <span class="attr">request</span>:    <span class="number">0.457</span> [ms]             <span class="comment">// 多久一个并发可得到结果</span></span><br><span class="line"><span class="title class_">Transfer</span> <span class="attr">rate</span>:       <span class="number">10876.09</span> [<span class="title class_">Kbytes</span>/sec] received      <span class="comment">// 吞吐量</span></span><br></pre></td></tr></table></figure>

<h2 id="性能分析"><a href="#性能分析" class="headerlink" title="性能分析"></a>性能分析</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、index.js：测试代码</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">end</span>(<span class="string">&#x27;hello world&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/index&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> file = fs.<span class="title function_">readFileSync</span>(__dirname + <span class="string">&#x27;/index.html&#x27;</span>, <span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line">    res.<span class="title function_">end</span>(file)</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、性能压测：可通过 ab、wrk、autocannon 等工具</span></span><br><span class="line">ab -c50 -t15 <span class="attr">http</span>:<span class="comment">//127.0.0.1:3000/index   // 执行一次 15s 的压测</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3-1、分析方式一：NodeJS 内置工具 profile。</span></span><br><span class="line">node --prof index.<span class="property">js</span>   <span class="comment">// 启动程序生成v8日志 isolate-0xa-20-v8.log</span></span><br><span class="line">node --prof-process isolate-<span class="number">0xa</span>-<span class="number">20</span>-v8.<span class="property">log</span> &gt; profile.<span class="property">json</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3-2、分析方式二：chrome devtools  </span></span><br><span class="line">node --inspect-brk index.<span class="property">js</span>    <span class="comment">// -brk 启动调试时首行代码处设置断点</span></span><br><span class="line"><span class="attr">chrome</span>:<span class="comment">//inspect               // chrome 地址栏打开后点击 inspect</span></span><br><span class="line">面板 performance 勾选 <span class="title class_">Memory</span> --&gt; 面板 <span class="title class_">Memory</span> --&gt; 左上角删除图标清空 </span><br><span class="line">--&gt; 点击左上角圆点生成快照 --&gt; 多个快照之间对比以下信息：shallow size</span><br><span class="line">为对象本身占用内存、retained size 为对象及其引用的对象 <span class="title class_">Shallow</span> <span class="title class_">Size</span></span><br><span class="line">retained size 如果远大于 shallow size，就说明这里有泄漏。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 4、代码优化：重新压测可看到 qps 已增加。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> readFileSync：分析出耗费时间最长，改为只读一次。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Stream.pipe：通过管道将文件数据以流的形式返回。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> <span class="variable">utf</span>-8：不指定格式时默认 buffer，代码效率更高。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">const</span> cache = []            <span class="comment">// 用于下面内存泄漏的测试。</span></span><br><span class="line"><span class="keyword">let</span> file = fs.<span class="title function_">readFileSync</span>(__dirname + <span class="string">&#x27;/index.html&#x27;</span>)</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/index&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    cache.<span class="title function_">push</span>(res)</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123;<span class="string">&#x27;Content-type&#x27;</span>: <span class="string">&#x27;text/html&#x27;</span>&#125;);</span><br><span class="line">    fs.<span class="title function_">createReadStream</span>(__dirname + <span class="string">&#x27;/index.html&#x27;</span>).<span class="title function_">pipe</span>(res);</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="内存机制"><a href="#内存机制" class="headerlink" title="内存机制"></a>内存机制</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、常驻内存：当前进程的所有内存，包括代码区、栈、堆、堆外内存。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 栈内存：一个成员大小固定、先进后出原则的数组结构，函数的参数、返回值、</span></span><br><span class="line"><span class="comment"> * 局部变量都存储在调用栈，函数调用时创建一个保存信息的新栈帧并在结束时自动释放。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 堆内存：一个成员大小不固定、先进先出原则的树状结构，存储了数组和函数</span></span><br><span class="line"><span class="comment"> * 等所有对象的地址指针，声明变量时创建，使用后由垃圾回收机制自动释放或手动释放。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 堆外内存：C++ 负责分配而不受 V8 管理的内存空间，比如 buffer 数据。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 2、Buffer 内存机制</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Buffer：JS 将对象存到堆并采用 slab 动态管理机制申请内存，Node C++ </span></span><br><span class="line"><span class="comment"> * 模块则负责分配对应堆外空间，堆外内存最终也间接被 JS 管理、V8 垃圾回收标记。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> slab：初始化时创建的一块 8KB slab 内存空间，Buffer.alloc(size) </span></span><br><span class="line"><span class="comment"> * 创建对象时去申请对应内存，如果小于 8KB 就分配 slab 剩余空间或新建一个 slab， </span></span><br><span class="line"><span class="comment"> * 大于时则直接使用 C++ SlowBuffer 提供空间而不需要频繁的分配操作。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 3、垃圾回收机制：内存分为新生代和老生代并分别使用复制和标记清除算法。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 新生代：V8 会将新建对象分配到 From 空间并在填满时将存活对象复制到 </span></span><br><span class="line"><span class="comment"> * To 空间、清空 From 空间、交换 From To 空间，执行快速但只能使用一半空间。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 老生代：新生代对象经过两轮回收之后就被晋升至老生代区，V8 从全局变量、</span></span><br><span class="line"><span class="comment"> * 当前执行的函数等根对象开始遍历所有对象并将可访问的设为已标记，清除未标记对象。</span></span><br><span class="line"><span class="comment"> * 内存空间一次清除后会出现不连续状态则需要通过增量标记和标记整理算法提升效率。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 4、内存泄露</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 出现场景：全局变量未清空、计时器和监听未清除、闭包的局部变量。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 高效使用：手动销毁变量 (delete 可能干扰 v8 而建议赋值空)、慎用闭包、</span></span><br><span class="line"><span class="comment"> * 文件操作时使用 stream 多次读取数据而避免一次占用过多堆空间、Buffer 对象及其</span></span><br><span class="line"><span class="comment"> * 储存数据分别保存育堆和堆外内存而在一定程度上节省了 V8 资源。</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 5、内存限制</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 原因：V8 垃圾回收会暂停 JS 线程，内存太大则回收时间太长。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 大小：64 位系统可以操纵 1.4GB，32 位系统可操纵 0.7GB。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 特例：通过 Node Buffer 可读取超过 V8 内存限制的大文件。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line">$ node</span><br><span class="line">&gt; process.<span class="title function_">memoryUsage</span>();              <span class="comment">// 当前进程的内存信息</span></span><br><span class="line">&#123; <span class="attr">rss</span>: <span class="number">14958592</span>,                      <span class="comment">// 当前进程的常驻内存</span></span><br><span class="line">  <span class="attr">heapTotal</span>: <span class="number">7195904</span>,                 <span class="comment">// 当前堆的所有内存</span></span><br><span class="line">  <span class="attr">heapUsed</span>: <span class="number">2821496</span>,                  <span class="comment">// 当前堆已分配内存</span></span><br><span class="line">  <span class="attr">external</span>: <span class="number">8772</span>                      <span class="comment">// C/C++ 占用内存</span></span><br><span class="line">&#125;</span><br><span class="line">node --max-old-space-size=<span class="number">1700</span> t.<span class="property">js</span>   <span class="comment">// 设置老生代最大内存，单位 MB</span></span><br><span class="line">node --max-<span class="keyword">new</span>-space-size=<span class="number">1024</span> t.<span class="property">js</span>   <span class="comment">// 设置新生代最大内存，单位 KB</span></span><br></pre></td></tr></table></figure>





    </div>

    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;margin-top:20px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>chuangges
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://chuangges.gitee.io/2019/06/16/7-1-Node%E5%9F%BA%E7%A1%80/" title="Node.js 主要内容">https://chuangges.gitee.io/2019/06/16/7-1-Node基础/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh_CN" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2019/06/10/5-2-vue%E5%B8%B8%E8%A7%81%E5%9C%BA%E6%99%AF/" rel="prev" title="Vue 常见场景的解决方案">
      <i class="fa fa-chevron-left"></i> Vue 常见场景的解决方案
    </a></div>
      <div class="post-nav-item">
    <a href="/2019/06/20/7-2-Node%E6%A1%86%E6%9E%B6/" rel="next" title="Node.js 常用框架">
      Node.js 常用框架 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E5%9F%BA%E7%A1%80%E4%BB%8B%E7%BB%8D"><span class="nav-number">1.</span> <span class="nav-text">一、基础介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%90%E8%A1%8C%E6%9C%BA%E5%88%B6"><span class="nav-number">1.1.</span> <span class="nav-text">运行机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8A%9F%E8%83%BD%E6%9E%B6%E6%9E%84"><span class="nav-number">1.2.</span> <span class="nav-text">功能架构</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE"><span class="nav-number">1.3.</span> <span class="nav-text">安装配置</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E6%A8%A1%E5%9D%97%E6%9C%BA%E5%88%B6"><span class="nav-number">2.</span> <span class="nav-text">二、模块机制</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E5%9D%97%E8%A7%84%E8%8C%83"><span class="nav-number">2.1.</span> <span class="nav-text">模块规范</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97"><span class="nav-number">2.2.</span> <span class="nav-text">核心模块</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Stream-%E6%B5%81"><span class="nav-number">2.3.</span> <span class="nav-text">Stream 流</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E8%BF%9B%E7%A8%8B%E6%9C%BA%E5%88%B6"><span class="nav-number">3.</span> <span class="nav-text">三、进程机制</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4"><span class="nav-number">3.1.</span> <span class="nav-text">常用命令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86"><span class="nav-number">3.2.</span> <span class="nav-text">进程管理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E8%BF%9B%E7%A8%8B%E6%9E%B6%E6%9E%84"><span class="nav-number">3.3.</span> <span class="nav-text">多进程架构</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1"><span class="nav-number">3.4.</span> <span class="nav-text">多进程通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%9E%B6%E6%9E%84"><span class="nav-number">3.5.</span> <span class="nav-text">多线程架构</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="nav-number">4.</span> <span class="nav-text">四、应用场景</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%90%AD%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="nav-number">4.1.</span> <span class="nav-text">搭建服务器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%9E%E6%8E%A5-mysql"><span class="nav-number">4.2.</span> <span class="nav-text">连接 mysql</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6"><span class="nav-number">4.3.</span> <span class="nav-text">上传文件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#WebSocket"><span class="nav-number">4.4.</span> <span class="nav-text">WebSocket</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%A7%A3%E5%86%B3%E8%B7%A8%E5%9F%9F"><span class="nav-number">4.5.</span> <span class="nav-text">解决跨域</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="nav-number">4.6.</span> <span class="nav-text">错误处理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%AD%E9%97%B4%E4%BB%B6"><span class="nav-number">4.7.</span> <span class="nav-text">中间件</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96"><span class="nav-number">5.</span> <span class="nav-text">五、性能优化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95"><span class="nav-number">5.1.</span> <span class="nav-text">性能测试</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90"><span class="nav-number">5.2.</span> <span class="nav-text">性能分析</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%86%85%E5%AD%98%E6%9C%BA%E5%88%B6"><span class="nav-number">5.3.</span> <span class="nav-text">内存机制</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="chuangges" src="" data-original="/images/chuang.png">
  <p class="site-author-name" itemprop="name">chuangges</p>
  <div class="site-description" itemprop="description">chuangge's blog.</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/chuangges" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;chuangges" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/yourname" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;yourname" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-stack-overflow fa-fw"></i>StackOverflow</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://juejin.im/" title="https:&#x2F;&#x2F;juejin.im&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">掘金</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.nowcoder.com/" title="https:&#x2F;&#x2F;www.nowcoder.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">牛客网</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.docschina.org/" title="https:&#x2F;&#x2F;www.docschina.org&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">印记中文</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://tool.lu/" title="http:&#x2F;&#x2F;tool.lu&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">在线工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tinypng.com/" title="https:&#x2F;&#x2F;tinypng.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片压缩</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://bigjpg.com/" title="https:&#x2F;&#x2F;bigjpg.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片放大</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tool.chinaz.com/" title="https:&#x2F;&#x2F;tool.chinaz.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">站长工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://learn-anything.xyz/" title="https:&#x2F;&#x2F;learn-anything.xyz&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Learn-Anything</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://stackoverflow.com/" title="https:&#x2F;&#x2F;stackoverflow.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Stack-Overflow</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">chuangge</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">1m</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">15:14</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","model":{"jsonPath":"/live2dw/assets/tororo.model.json"},"display":{"position":"left","width":180,"height":360},"mobile":{"show":false},"react":{"opacityDefault":1,"opacityOnHover":1},"log":false,"tagMode":false});</script>
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(e){e.imageLazyLoadSetting.processImages=t;var n=e.imageLazyLoadSetting.isSPA,i=e.imageLazyLoadSetting.preloadRatio||1,r=o();function o(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){n&&(r=o());for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(e.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];e=function(){r=r.filter(function(t){return o!==t})},(t=o).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,t.removeAttribute("data-original"),e&&e()},t.src!==i&&(n.src=i))}()}function a(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",a),e.addEventListener("resize",a),e.addEventListener("orientationchange",a)}(this);</script></body>
</html>
